package com.shm.leetcode;

/**
 * 剑指 Offer 36. 二叉搜索树与双向链表
 * 输入一棵二叉搜索树，将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点，只能调整树中节点指针的指向。
 * 为了让您更好地理解问题，以下面的二叉搜索树为例：
 *
 *
 * 我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表，第一个节点的前驱是最后一个节点，最后一个节点的后继是第一个节点。
 *
 * 下图展示了上面的二叉搜索树转化成的链表。“head” 表示指向链表中有最小元素的节点。
 *
 * 特别地，我们希望可以就地完成转换操作。当转化完成以后，树中节点的左指针需要指向前驱，树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。
 * 注意：本题与主站 426 题相同：https://leetcode-cn.com/problems/convert-binary-search-tree-to-sorted-doubly-linked-list/
 * 注意：此题对比原题有改动。
 * @author SHM
 */
public class TreeToDoublyList {

// Definition for a Node.
class Node {
    public int val;
    public Node left;
    public Node right;

    public Node() {}

    public Node(int _val) {
        val = _val;
    }

    public Node(int _val,Node _left,Node _right) {
        val = _val;
        left = _left;
        right = _right;
    }
};

    class Solution {
        //把每个结点的left看作双向链表里的pre，right看作双向链表里的next，更容易理解
        Node head = null;
        Node pre = null;

        /**
         * 解题思路：
         * 本文解法基于性质：二叉搜索树的中序遍历为 递增序列 。
         * 将 二叉搜索树 转换成一个 “排序的循环双向链表” ，其中包含三个要素：
         *
         * 排序链表： 节点应从小到大排序，因此应使用 中序遍历 “从小到大”访问树的节点；
         * 双向链表： 在构建相邻节点（设前驱节点 prepre ，当前节点 curcur ）关系时，不仅应 pre.right = curpre.right=cur ，也应 cur.left = precur.left=pre 。
         * 循环链表： 设链表头节点 headhead 和尾节点 tailtail ，则应构建 head.left = tailhead.left=tail 和 tail.right = headtail.right=head 。
         *
         * 作者：jyd
         * 链接：https://leetcode-cn.com/problems/er-cha-sou-suo-shu-yu-shuang-xiang-lian-biao-lcof/solution/mian-shi-ti-36-er-cha-sou-suo-shu-yu-shuang-xian-5/
         * @param root
         * @return
         */
        public Node treeToDoublyList(Node root) {
            if(root==null){
                return null;
            }
            travel(root);
            //中序遍历处理过后只是形成了一个双向链表
            //让头结点的pre指向尾结点，尾结点的next指向头，才形成循环
            head.left = pre;
            pre.right = head;
            return head;
        }
        public void travel(Node root){
            if(root==null){
                return;
            }
            travel(root.left);
            //如果头结点为空，说明这是双向链表里的第一个结点
            //对头结点只需要处理它的next指针，也就是root.left = pre;
            if(head==null){
                head = root;
            } else {
                //不为头结点时不仅需要处理它自身的next指针（root.left = pre）
                //还需要让链表前一结点的next指向当前节点，也就是pre.right = root;
                pre.right = root;
            }
            //
            root.left = pre;
            pre = root;
            travel(root.right);
        }
    }
}
